import { Injectable, EventEmitter } from '@angular/core';

// If you import a module but never use any of the imported values other than as TypeScript types,
// the resulting javascript file will look as if you never imported the module at all.
import { ipcRenderer, webFrame, remote, shell, BrowserWindow } from 'electron';
import * as childProcess from 'child_process';
import * as fs from 'fs';
import * as Url from 'url';
import * as Path from 'path';
import { DiskInfo } from '../models/diskinfo';
import { FileInfo } from '../models/fileinfo';
import { CustomOpenDialogOptions } from '../models/options';

@Injectable()
export class ElectronService {

  ipcRenderer: typeof ipcRenderer;
  webFrame: typeof webFrame;
  remote: typeof remote;
  childProcess: typeof childProcess;
  fs: typeof fs;
  onSelectedFiles = new EventEmitter<string[]>();
  onSelectedDirectorys = new EventEmitter<string[]>();
  constructor() {
    // Conditional imports
    if (this.isElectron()) {
      this.ipcRenderer = window.require('electron').ipcRenderer;
      this.webFrame = window.require('electron').webFrame;
      this.remote = window.require('electron').remote;

      this.childProcess = window.require('child_process');
      this.fs = window.require('fs');

      this.ipcRenderer.on('selectedfileordirectory', (_event, _args) => {
        if (_args && _args.hasOwnProperty('type')) {
          const type = _args['type'];
          let result: any;
          if (_args.hasOwnProperty('result')) {
            result = _args['result'];
          }

          if (result) {
            if (type === 'file') {
              this.onSelectedFiles.emit(result);
            } else {
              this.onSelectedDirectorys.emit(result);
            }
          }
        }
      });
    }
  }

  /**判断是否为electron */
  isElectron = () => {
    return window && window.process && window.process.type;
  }
  /**
   * 打开开发者工具
   */
  openDevTools() {
    if (this.isElectron) {
      const currentWebContents = this.remote.getCurrentWebContents();
      if (currentWebContents) {
        currentWebContents.openDevTools();
      }
    }
  }
  /**
   * 关闭开发者工具
   */
  closeDevTools() {
    if (this.isElectron) {
      const currentWebContents = this.remote.getCurrentWebContents();
      if (currentWebContents) {
        currentWebContents.closeDevTools();
      }
    }
  }
  /** 获取临时文件夹路径 */
  getTempPath() {
    return this.getSpecialPath('temp');
  }
  /** 获取桌面文件夹路径 */
  getDesktopPath() {
    return this.getSpecialPath('desktop');
  }
  /** 获取用户文档文件夹路径 */
  getDocumentsPath() {
    return this.getSpecialPath('documents');
  }
  /** 获取用户下载文件夹路径 */
  getDownloadsPath() {
    return this.getSpecialPath('downloads');
  }
  /** 获取用户视频文件夹路径 */
  getVideosPath() {
    return this.getSpecialPath('videos');
  }
  /** 获取用户图片文件夹路径 */
  getPicturesPath() {
    return this.getSpecialPath('pictures');
  }
  getSpecialPath(name: string) {
    if (!this.isElectron) {
      return null;
    }
    return remote.app.getPath(name);
  }
  /**
   * 获取当前窗口
   */
  getCurrentWindow(): Electron.BrowserWindow {
    if (this.isElectron) {
      return this.remote.getCurrentWindow();
    }
    return null;
  }
  /**
   * 获取当前拥有焦点的窗口
   */
  getCurrentFocusWindow(): Electron.BrowserWindow {
    if (this.isElectron) {
      return this.remote.BrowserWindow.getFocusedWindow();
    }
    return null;
  }
  /**
   * 获取当前窗口标题
   */
  getCurrentWindowTitle(): string {
    const currentWindow = this.getCurrentWindow();
    if (currentWindow) {
      return currentWindow.getTitle();
    }
    return null;
  }
  /**
   * 获取当前拥有焦点的窗口标题
   */
  getCurrentFocusWindowTitle(): string {
    const currentWindow = this.getCurrentFocusWindow();
      if (currentWindow) {
        return currentWindow.getTitle();
      }
    return null;
  }
  /**
   * 获取当前操作系统登录用户的根目录
   * 如：c:\C:\Users\Administrator\
  */
  get currentSysUserPath() {
    const os = require('os');
    return `${os.homedir()}\\`;
  }
  /**
   * 获取当前操作登录用户的临时目录
   */
  get currentSysUserTempPath() {
    const os = require('os');
    return `${os.tmpdir()}\\`;
  }
  /**
   * 最小化指定窗口
   * @param window 待最小化的窗口
   */
  minimizeWindow(window: BrowserWindow) {
    if (this.isElectron && window) {
      window.minimize();
    }
  }
  /**
   * 最大化指定窗口
   * @param window 待最大化的窗口
   */
  maxtWindow(window: BrowserWindow) {
    if (this.isElectron && window) {
      if (!window.isMaximized()) {
        window.maximize();
      }
    }
  }
  /**
   * 恢复指定窗口
   * @param window 待恢复的窗口
   */
  restoreWindow(window: BrowserWindow) {
    if (this.isElectron && window) {
      if (window.isMaximized()) {
        window.unmaximize();
      }
    }
  }
  /**
   * 最大化或恢复指定窗口
   * @param window 待最大化或恢复窗口
   */
  maxOrRestoreWindow(window: BrowserWindow) {
    if (this.isElectron && window) {
      if (!window.isMaximized()) {
        window.maximize();
      } else {
        window.unmaximize();
      }
    }
  }
  /**
   * 关闭指定窗口
   * @param window 待关闭的窗口
   */
  closeWindow(window: BrowserWindow) {
    if (this.isElectron && window) {
      window.close();
    }
  }
  /**
   * 打开窗口
   * @param url 窗口url
   * @param options 创建窗口选项
   * @param configWindow 窗口配置处理参数
   */
  openWindow(url: string, options?: Electron.BrowserWindowConstructorOptions
    , configWindow?: (w: BrowserWindow) => void) {
    let win = new this.remote.BrowserWindow(options);
    win.on('close', event => {
      win = null;
    });
    if (configWindow) {
      configWindow(win);
    }
    if (location.protocol === 'http:') {
        win.loadURL(`${location.origin}/#/${url}`);
      } else {
        win.loadURL(Url.format({
            pathname: Path.join(__dirname, './index.html'),
            protocol: 'file:',
            slashes: true,
            hash: url
          }));
      }
      win.show();
  }
  /**
   * 打开指定文件
   * @param file 待打开的文件路径
   */
  openFile(file: string) {
    if (this.isElectron) {
      shell.openItem(file);
    }
  }
  /**
   * 打开指定url
   * @param url 待打开的url
   */
  openUrl(url: string) {
    if (this.isElectron) {
      shell.openExternal(url);
    }
  }
  /**
   * 显示目录选择对话框
   * @param muti 标识是否允许多选，默认为false
   */
  showDirectorySelectDialog(muti?: boolean) {
    const options = new CustomOpenDialogOptions();
    options.properties = ['openDirectory'];
    if (muti !== null) {
      options.properties.push('multiSelections');
    }
    this.ipcRenderer.send('selectfileordirectory', options);
  }
  /**
   * 显示文件选择对话框
   * @param muti 标识是否允许多选，默认为false
   */
  showFileSelectDialog(muti?: boolean) {
    const options = new CustomOpenDialogOptions();
    options.properties = ['openFile'];
    if (muti !== null) {
      options.properties.push('multiSelections');
    }
    this.ipcRenderer.send('selectfileordirectory', options);
  }
  /**
   * 获取指定目录包含的文件
   * @param path 检索的目录
   * @param includeDirectory 表示是否包含目录，如果位false则只列出检索目录中的文件
   */
  async enumFiles(path: string , includeDirectory: boolean = true) {
    const util = require('util');
    const read = util.promisify(this.innerEenumsFile);
    const files = await read(path, includeDirectory);
    return files;
  }

  /**
   * 获取所有逻辑磁盘信息
   */
  async enumDisks() {
    const disks: DiskInfo[] = [];
    const util = require('util');
    const exec = util.promisify(require('child_process').exec);
    const { stdout, stderr } = await exec('wmic logicaldisk get filesystem,freespace,name,size,volumename'
    , {encoding: 'ascii'});
    const arrays: string[] = stdout.split('\n');
    for (let index = 0; index < arrays.length; index++) {
      if (index > 0) {
        const item = arrays[index];
        if (item.trim() !== '') {
          const values = item.split(' ');
          const destValues = [];
          values.forEach(value => {
            const _value = value.trim();
            if (_value !== '') {
              destValues.push(_value);
            }
          });
          if (destValues && destValues.length >= 4) {
            const diskInfo = new DiskInfo();
            diskInfo.fileSystem = destValues.length >= 1 ? destValues[0] : '';
            if (destValues.length >= 2) {
              diskInfo.setFreeSpace(destValues[1]);
            }
            if (destValues.length >= 3) {
              diskInfo.setName(destValues[2]);
            }
            if (destValues.length >= 4) {
              diskInfo.setSize(destValues[3]);
            }
            if (destValues.length >= 5) {
              diskInfo.volumeName = destValues[4];
            }
            diskInfo.refreshDetailInfo();
            disks.push(diskInfo);
          }
        }
      }
    }
    return disks;
  }
  /**
   * 获取指定目录包含的文件
   * @param path 检索的目录
   * @param includeDirectory 表示是否包含目录，如果位false则只列出检索目录中的文件
   * @param callBack 回调处理方法
   */
  private innerEenumsFile(path: string, includeDirectory: boolean
    , callBack: (error: any, files: FileInfo[]) => void) {
    const destFiles: FileInfo[] = [];
    const destDirectorys: FileInfo[] = [];
    fs.readdir(path, function(err, files) {
      const dirs = [];
      if (!err) {
        if (files && files.length > 0) {
          (function iterator(i) {
            if (i === files.length) {
              if (callBack) {
                callBack(null, destDirectorys.concat(destFiles));
              }
              return ;
            }

            const file = files[i];
            const file_info = new FileInfo();
            file_info.filePath = Path.resolve(path, file);
            file_info.fileName = Path.basename(file);
            fs.stat(file_info.filePath, function(_err, data) {
              if (!err && data) {
                if (data.isFile()) {
                  file_info.setFile();
                  destFiles.push(file_info);
                  const ext = Path.extname(file_info.filePath);
                  file_info.setExt(ext);
                }
                if (data.isDirectory() && includeDirectory) {
                  file_info.setDirectory();
                  destDirectorys.push(file_info);
                }
                file_info.fileLength = data.size;
              }
              iterator(i + 1);
            });
          })(0);
        } else {
          callBack(null, null);
        }
      } else if (callBack) {
        callBack(err, null);
      }
    });
  }
}
